﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace IndexedList
{
    public class UniqueListIndex<T> : BaseListIndex<T> where T : new()
    {
        Dictionary<long, T> IndexData = new Dictionary<long, T>();

        public UniqueListIndex(ISet<string> fieldNames)
            : base(fieldNames)
        {
        }

        public UniqueListIndex(Expression<Func<T, object>> expression)
            : base(expression)
        {
        }

        public UniqueListIndex(string name, Expression<Func<T, object>> expression)
            : base(name, expression)
        {
        }

        public UniqueListIndex(string name, HashSet<string> fieldNames)
            : base(name, fieldNames)
        {
        }

        public override void IndexItem(T data)
        {
            int Key = ItemHashFunction(data);
            if (IndexData.ContainsKey(Key))
            {
                T item = IndexData[Key];
                foreach (var fieldinfo in this.IndexFields.Values)
                {
                    if (!Equals(fieldinfo.GetValue(item, null), fieldinfo.GetValue(data, null)))
                    {
                        throw new Exception("Duplicate hash found in data");
                    }
                }
                throw new InvalidOperationException("Cannot insert duplicate value for Index: " + this.Name);
            }
            IndexData.Add(Key, data);
        }

        protected override IEnumerable<T> FindItems(int key)
        {
            if (!IndexData.ContainsKey(key))
                return new List<T> { };
            return new List<T> { IndexData[key] };
        }

        protected override T FindSingleItem(int Key)
        {
            if (!IndexData.ContainsKey(Key))
                return default(T);
            return IndexData[Key];
        }

        public override void ClearIndexData()
        {
            this.IndexData.Clear();
        }

        public override void RemoveIndex(T item)
        {
            int key = this.ItemHashFunction(item);
            if (this.IndexData.ContainsKey(key))
                this.IndexData.Remove(key);
        }
    }

    public static class UniqueListIndexExtensionMethods
    {
        public static void AddUniqueIndex<T>(this IList<T> list, Expression<Func<T, object>> expression, string name = "") where T : new()
        {
            IndexedList<T> indexedlist = list as IndexedList<T>;
            if (indexedlist != null)
                indexedlist.AddIndex(new UniqueListIndex<T>(name, expression));
        }
    }

}
